<!doctype html>



  


<html class="theme-next mist use-motion" lang="zh-Hans">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>



<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />












  
  
  <link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />




  
  
  
  

  
    
    
  

  

  

  

  

  
    
    
    <link href="//fonts.googleapis.com/css?family=Lato:300,300italic,400,400italic,700,700italic&subset=latin,latin-ext" rel="stylesheet" type="text/css">
  






<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />

<link href="/css/main.css?v=5.1.0" rel="stylesheet" type="text/css" />


  <meta name="keywords" content="javascript,coffeescript," />








  <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico?v=5.1.0" />






<meta name="description" content="注记转载自lilu发表的文章coffeescript详解，文章所有权利归原作者所有。
这是今年年初学习CoffeeScript的一篇个人总结，觉得也许会对社区有些帮助，就从我的博客转来了这里，因为水平有限，错漏之处在所难免，希望高手指点">
<meta property="og:type" content="article">
<meta property="og:title" content="CoffeeScript 详解(转载)">
<meta property="og:url" content="http://chrisrc.me/2016/04/25/web-js-coffeescript/index.html">
<meta property="og:site_name" content="山中，山外与俯瞰">
<meta property="og:description" content="注记转载自lilu发表的文章coffeescript详解，文章所有权利归原作者所有。
这是今年年初学习CoffeeScript的一篇个人总结，觉得也许会对社区有些帮助，就从我的博客转来了这里，因为水平有限，错漏之处在所难免，希望高手指点">
<meta property="og:updated_time" content="2016-12-17T07:29:29.000Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="CoffeeScript 详解(转载)">
<meta name="twitter:description" content="注记转载自lilu发表的文章coffeescript详解，文章所有权利归原作者所有。
这是今年年初学习CoffeeScript的一篇个人总结，觉得也许会对社区有些帮助，就从我的博客转来了这里，因为水平有限，错漏之处在所难免，希望高手指点">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Mist',
    sidebar: {"position":"left","display":"post"},
    fancybox: true,
    motion: true,
    duoshuo: {
      userId: '0',
      author: '博主'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="http://chrisrc.me/2016/04/25/web-js-coffeescript/"/>





  <title> CoffeeScript 详解(转载) | 山中，山外与俯瞰 </title>
</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">

  










  
  
    
  

  <div class="container one-collumn sidebar-position-left page-post-detail ">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-meta ">
  

  <div class="custom-logo-site-title">
    <a href="/"  class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <span class="site-title">山中，山外与俯瞰</span>
      <span class="logo-line-after"><i></i></span>
    </a>
  </div>
  <p class="site-subtitle">一次永不停止的探索之旅</p>
</div>

<div class="site-nav-toggle">
  <button>
    <span class="btn-bar"></span>
    <span class="btn-bar"></span>
    <span class="btn-bar"></span>
  </button>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-dcos">
          <a href="/dcos" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-book"></i> <br />
            
            DC/OS
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/categories" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-th"></i> <br />
            
            分类
          </a>
        </li>
      
        
        <li class="menu-item menu-item-about">
          <a href="/about" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-user"></i> <br />
            
            关于
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
            
            归档
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/tags" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-tags"></i> <br />
            
            标签
          </a>
        </li>
      

      
        <li class="menu-item menu-item-search">
          
            <a href="javascript:;" class="st-search-show-outputs">
          
            
              <i class="menu-item-icon fa fa-search fa-fw"></i> <br />
            
            搜索
          </a>
        </li>
      
    </ul>
  

  
    <div class="site-search">
      
  <form class="site-search-form">
  <input type="text" id="st-search-input" class="st-search-input st-default-search-input" />
</form>

<script type="text/javascript">
  (function(w,d,t,u,n,s,e){w['SwiftypeObject']=n;w[n]=w[n]||function(){
    (w[n].q=w[n].q||[]).push(arguments);};s=d.createElement(t);
    e=d.getElementsByTagName(t)[0];s.async=1;s.src=u;e.parentNode.insertBefore(s,e);
  })(window,document,'script','//s.swiftypecdn.com/install/v2/st.js','_st');

  _st('install', 'R9GcmhBwxpsAGLNCsquZ','2.0.0');
</script>



    </div>
  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
  <link itemprop="mainEntityOfPage" href="http://chrisrc.me/2016/04/25/web-js-coffeescript/">

  <span style="display:none" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <meta itemprop="name" content="chrisrc">
    <meta itemprop="description" content="">
    <meta itemprop="image" content="/images/avatar.gif">
  </span>

  <span style="display:none" itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
    <meta itemprop="name" content="山中，山外与俯瞰">
    <span style="display:none" itemprop="logo" itemscope itemtype="http://schema.org/ImageObject">
      <img style="display:none;" itemprop="url image" alt="山中，山外与俯瞰" src="">
    </span>
  </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                CoffeeScript 详解(转载)
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>
              <time title="Post created" itemprop="dateCreated datePublished" datetime="2016-04-25T14:10:18+08:00">
                2016-04-25
              </time>
            

            

            
          </span>

          
            <span class="post-category" >
              <span class="post-meta-divider">|</span>
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/JavaScript/" itemprop="url" rel="index">
                    <span itemprop="name">JavaScript</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <a href="/2016/04/25/web-js-coffeescript/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count ds-thread-count" data-thread-key="2016/04/25/web-js-coffeescript/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          

          
          

          

          

        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        <h2 id="注记"><a href="#注记" class="headerlink" title="注记"></a>注记</h2><p>转载自<a href="https://ruby-china.org/lilu" target="_blank" rel="external">lilu</a>发表的文章<a href="https://ruby-china.org/topics/4789" target="_blank" rel="external">coffeescript详解</a>，文章所有权利<br>归原作者所有。</p>
<p>这是今年年初学习CoffeeScript的一篇个人总结，觉得也许会对社区有些帮助，就从我的博客转来了这里，因为水平有限，错漏之处在所难免，希望高手指点</p>
<a id="more"></a>
<h2 id="序"><a href="#序" class="headerlink" title="序"></a>序</h2><blockquote>
<p>&gt;<br>Every language feature in CoffeeScript has been designed using this kind of process:<br>attempt to take the beautiful dynamic semantics of JavaScript—object literals, function expressions, prototypal inheritance—and express them in a clean, readable, minimal way.<br>by Jeremy Ashkenas, author of CoffeeScript</p>
</blockquote>
<p>CoffeeScript是一门简洁的，构架于JavaScript之上的预处理器语言，可以静态编译成JavaScript，语法主要受ruby和python影响，目前已经为众多rails和node项目采用。</p>
<h3 id="为什么要用CoffeeScript"><a href="#为什么要用CoffeeScript" class="headerlink" title="为什么要用CoffeeScript?"></a>为什么要用CoffeeScript?</h3><ul>
<li>更少，更紧凑，和更清晰的代码</li>
<li>通过规避和改变对JavaScript中不良部分的使用，只留下精华，让代码减少出错率，更容易维护</li>
<li>在很多常用模式的实现上采用了JavaScript中的最佳实践</li>
<li>CoffeeScript生成的JavaScript代码都可以完全通过JSLint的检测</li>
</ul>
<h3 id="什么情况下不推荐使用CoffeeScript"><a href="#什么情况下不推荐使用CoffeeScript" class="headerlink" title="什么情况下不推荐使用CoffeeScript?"></a>什么情况下不推荐使用CoffeeScript?</h3><p>CoffeeScript不是JavaScript的超集，也不是完全替代品，不应该在不会JavaScript的情况下使用CoffeeScript工作<br>CoffeeScript是一种需要预编译的语言，不能在运行时(Runtime)解释，这造成了她普遍被人质疑的一点，就是如果代码中出现运行时错误时难以调试，不过从实际使用上来看，因为CoffeeScript的编译结果大部分情况下自然而合理，至少我从来没有发现从生成的JavaScript代码回溯到对应的CoffeeScript代码有什么困难之处，我们稍后会看到这种对应关系的细节</p>
<p>这种静态编译还有一个额外的好处，就是CoffeeScript和现有的环境(浏览器,Node,Rhino等)与库完全兼容</p>
<p>最简单的安装和测试CoffeeScript的方法，是使用<em>node.js</em>的<em>npm</em>安装，然后使用命令行脚本实时编译</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">npm install -g coffee-script</div><div class="line"># watch and compile</div><div class="line">coffee -w --output lib --compile src</div></pre></td></tr></table></figure>
<p>这里假设你的coffee代码在src目录下，这个daemon会自动检测文件的改变，并编译成js文件放到lib目录下</p>
<h3 id="语法"><a href="#语法" class="headerlink" title="语法"></a>语法</h3><p>与SASS/LESS和CSS的关系不同，CoffeeScript不是JavaScript的超集，不能在CoffeeScript程序中写JavaScript代码，比如function等关键字</p>
<h3 id="格式"><a href="#格式" class="headerlink" title="格式"></a>格式</h3><p>在js中，如果认为当前语句和随后语句是一个整体的话，就不会自己加;，比如以下javascript代码</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//javascript code</span></div><div class="line"><span class="keyword">var</span> y = x+f</div><div class="line">(a+b).toString()</div><div class="line"></div><div class="line"><span class="comment">//parsed to:</span></div><div class="line"><span class="keyword">var</span> y = x+f(a+b).toString();</div></pre></td></tr></table></figure>
<p>很多js中的问题由此引起(实际上现在把;放在哪里，在js社区内也是个争论的话题)</p>
<p>而CoffeeScript在编译时为每条语句加上;，因此在代码中不需要写;</p>
<p>CoffeeScript中的注释采用#</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"># single line comment</div><div class="line">###</div><div class="line">  multi line comment</div><div class="line">###</div></pre></td></tr></table></figure>
<p>CoffeeScript中对空白敏感，这种做法来自python，任何需要({})的场合下，可以用缩进代替</p>
<h3 id="作用域"><a href="#作用域" class="headerlink" title="作用域"></a>作用域</h3><p>在js中最糟糕的设计就是全局变量，当你忘记用var声明变量的时候，这个变量会成为全局对象上的一个属性</p>
<p>CoffeeScript避免了这点</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">foo = <span class="string">"bar"</span></div></pre></td></tr></table></figure>
<p>会编译成</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</div><div class="line">  <span class="keyword">var</span> foo;</div><div class="line">  foo = <span class="string">"bar"</span>;</div><div class="line">&#125;).call(<span class="keyword">this</span>);</div></pre></td></tr></table></figure>
<p>任何的代码都会使用<em>Immediate Function</em>包装，这样foo成为了本地变量，并且，可以通过call指定的this引用全局对象</p>
<p>为了方便起见，之后的编译后代码描述不会再加上这个包装</p>
<p>实际上在CoffeeScript中，你也不需要再用var声明变量，编译后会自动加上var，并且将声明<em>hoisting</em>，即放到作用域的顶部，看一个来自官方文档的例子</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">outer = <span class="number">1</span></div><div class="line">change = -&gt;</div><div class="line">  inner = <span class="number">-1</span></div><div class="line">  outer = <span class="number">10</span></div><div class="line">inner = change()</div></pre></td></tr></table></figure>
<p><strong>-&gt;</strong> 是函数定义的简写方式，之后我们会探讨</p>
<p>编译后的js如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> change, inner, outer;</div><div class="line"></div><div class="line">outer = <span class="number">1</span>;</div><div class="line"></div><div class="line">change = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</div><div class="line">  <span class="keyword">var</span> inner;</div><div class="line">  inner = <span class="number">-1</span>;</div><div class="line">  <span class="keyword">return</span> outer = <span class="number">10</span>;</div><div class="line">&#125;;</div><div class="line"></div><div class="line">inner = change();</div></pre></td></tr></table></figure>
<p>这是类似ruby中的自然的作用域实现方式，inner在change()内定义成了局部变量，因为在代码中之前没有定义过</p>
<h3 id="赋值"><a href="#赋值" class="headerlink" title="赋值"></a>赋值</h3><p>首先是字符串可以用类ruby的语法内嵌</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">target = <span class="string">"world"</span></div><div class="line">alert <span class="string">"hello, #&#123;target&#125;"</span></div></pre></td></tr></table></figure>
<p>其次是字面量，可以用类似<em>YAML</em>的方法定义对象字面量</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">object1 = one: 1, two: 2</div><div class="line">object2 =</div><div class="line">  one: 1</div><div class="line">  two: 2</div><div class="line">  class: "numbers"</div></pre></td></tr></table></figure>
<p>注意保留字class，现在可以直接作为对象的key了</p>
<p>数组也可以分行</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">arr = [</div><div class="line">  <span class="number">1</span></div><div class="line">  <span class="number">2</span></div><div class="line">]</div></pre></td></tr></table></figure>
<p>也可以解构赋值(Destructuring)</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">obj = &#123;<span class="attr">a</span>:<span class="string">"foo"</span>, <span class="attr">b</span>:<span class="string">"bar"</span>&#125;</div><div class="line">&#123;a, b&#125; = obj</div><div class="line">arr = [<span class="number">1</span>, <span class="number">2</span>]</div><div class="line">[a, b] = arr</div></pre></td></tr></table></figure>
<h3 id="数组"><a href="#数组" class="headerlink" title="数组"></a>数组</h3><p>数组的操作引入了来自ruby的Range概念，并且可以将字符串完全作为数组操作</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">numbers = [<span class="number">0.</span><span class="number">.9</span>]</div><div class="line">numbers[<span class="number">3.</span><span class="number">.5</span>] = [<span class="number">-3</span>, <span class="number">-4</span>, <span class="number">-5</span>]</div><div class="line">my = <span class="string">"my string"</span>[<span class="number">0.</span><span class="number">.1</span>]</div></pre></td></tr></table></figure>
<p>判断一个值是否在数组内，在js中可以用Array.prototype.indexOf，不过IE8及以下不支持，CoffeeScript提供了跨浏览器的in操作符解决</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">arr = [<span class="string">"foo"</span>, <span class="string">"bar"</span>]</div><div class="line"><span class="string">"foo"</span> <span class="keyword">in</span> arr</div></pre></td></tr></table></figure>
<p>具体的实现上，是一个对indexOf的Shim</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"> <span class="keyword">var</span> arr,</div><div class="line">   __indexOf = [].indexOf || <span class="function"><span class="keyword">function</span>(<span class="params">item</span>) </span>&#123;</div><div class="line">     <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>, l = <span class="keyword">this</span>.length; i &lt; l; i++) &#123;</div><div class="line">       <span class="keyword">if</span> (i <span class="keyword">in</span> <span class="keyword">this</span> &amp;&amp; <span class="keyword">this</span>[i] === item)</div><div class="line">         <span class="keyword">return</span> i;</div><div class="line">     &#125;</div><div class="line">     <span class="keyword">return</span> <span class="number">-1</span>;</div><div class="line">   &#125;;</div><div class="line"></div><div class="line">arr = [<span class="string">"foo"</span>, <span class="string">"bar"</span>];</div><div class="line"></div><div class="line">__indexOf.call(arr, <span class="string">"foo"</span>) &gt;= <span class="number">0</span>;</div></pre></td></tr></table></figure>
<p><strong>for..in</strong> 语法可以用在数组上了，背后是用js的for循环实现的，这比数组的迭代器方法要效率高一些</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">for</span> name, i <span class="keyword">in</span> [<span class="string">"Roger"</span>, <span class="string">"Roderick"</span>]</div><div class="line">  alert <span class="string">"#&#123;i&#125; - Release #&#123;name&#125;"</span></div></pre></td></tr></table></figure>
<p>也具有过滤器when</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">prisoners = [<span class="string">"Roger"</span>, <span class="string">"Roderick"</span>, <span class="string">"Brian"</span>]</div><div class="line">release prisoner <span class="keyword">for</span> prisoner <span class="keyword">in</span> prisoners when prisoner[<span class="number">0</span>] is <span class="string">"R"</span></div></pre></td></tr></table></figure>
<p>看起来很像普通英语了，也可以用()收集遍历的结果</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">result = (item <span class="keyword">for</span> item <span class="keyword">in</span> array when item.name is <span class="string">"test"</span>)</div></pre></td></tr></table></figure>
<p>遍历对象的属性可以用of,这是用js自己的for..in实现的</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">names = sam: seaborn, <span class="attr">donna</span>: moss</div><div class="line">alert(<span class="string">"#&#123;first&#125; #&#123;last&#125;"</span>) <span class="keyword">for</span> first, last <span class="keyword">of</span> names</div></pre></td></tr></table></figure>
<h3 id="流程控制"><a href="#流程控制" class="headerlink" title="流程控制"></a>流程控制</h3><p>CoffeeScript使用来自ruby的省略语法，让控制流变得很紧凑，也引进了unless,not,then等语法糖式的关键字</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">result = <span class="keyword">if</span> not <span class="literal">true</span> then <span class="string">"false"</span></div><div class="line">result = unless <span class="literal">true</span> then <span class="string">"false"</span></div></pre></td></tr></table></figure>
<p>CoffeeScript中非常好的一点，就是直接取消了js中的==判断，改成全部用===进行严格比较，js中的==会做大量诡异的类型转换，很多情况下是bug的来源</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span> <span class="string">"1"</span> == <span class="number">1</span></div><div class="line">  alert(<span class="string">"equal"</span>)</div><div class="line"><span class="keyword">else</span></div><div class="line">  alert(<span class="string">"not equal"</span>)</div></pre></td></tr></table></figure>
<p>在使用if来进行空值的判断时，js有时会让人困扰，因为””和0都会被转换成false，Coffee提供了?操作符解决这个问题，她只有在变量为null或undefined时才为false</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">""? #true</div><div class="line">null? #false</div></pre></td></tr></table></figure>
<p>也可以用常见的类似ruby中||=的方法，判断赋值，此外还可以用and,or,is关键字代替&amp;&amp;,||,==</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">hash or= &#123;&#125;</div><div class="line">hash ?= &#123;&#125;</div></pre></td></tr></table></figure>
<p>经常有当某个属性存在的时候，才会调用属性上的方法的情况，这时候也可以用?</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">knight.hasSword()?.poke()</div></pre></td></tr></table></figure>
<p>只有当hasSword()返回对象不为空时，才会调用poke方法，以下是编译的js代码</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> _ref;</div><div class="line"><span class="keyword">if</span> ((_ref = knight.hasSword()) != <span class="literal">null</span>) &#123;</div><div class="line">  _ref.poke();</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>另一种情况是当poke方法存在时才调用</p>
<figure class="highlight coffeescript"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">knight.hasSword().poke?()</div></pre></td></tr></table></figure>
<p>对应的js代码</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> _base;</div><div class="line"><span class="keyword">if</span> (<span class="keyword">typeof</span> (_base = knight.hasSword()).poke === <span class="string">"function"</span>) &#123;</div><div class="line">  _base.poke();</div><div class="line">&#125;</div><div class="line"><span class="keyword">switch</span> <span class="keyword">case</span>语句也有了一些语法糖，并且会默认加上<span class="keyword">break</span></div><div class="line"></div><div class="line"><span class="string">``</span><span class="string">`js</span></div><div class="line">switch day</div><div class="line">  when "Sun" then go relax</div><div class="line">  when "Sat" then go dancing</div><div class="line">  else go work</div></pre></td></tr></table></figure>
<h3 id="函数"><a href="#函数" class="headerlink" title="函数"></a>函数</h3><p>CoffeeScript对JavaScript的函数做了很大的简化，举个例子，看一个求和函数</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">sum = (nums...) -&gt;</div><div class="line">  nums.reduce (x, y) -&gt; x+y</div><div class="line"></div><div class="line">sum <span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span></div></pre></td></tr></table></figure>
<p>对应JavaScript</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> sum,</div><div class="line">    __slice = [].slice;</div><div class="line"></div><div class="line">sum = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</div><div class="line">  <span class="keyword">var</span> nums;</div><div class="line">  nums = <span class="number">1</span> &lt;= <span class="built_in">arguments</span>.length ? __slice.call(<span class="built_in">arguments</span>, <span class="number">0</span>) : [];</div><div class="line">  <span class="keyword">return</span> nums.reduce(<span class="function"><span class="keyword">function</span>(<span class="params">x, y</span>) </span>&#123;</div><div class="line">    <span class="keyword">return</span> x + y;</div><div class="line">  &#125;);</div><div class="line">&#125;;</div><div class="line"></div><div class="line">sum(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>);</div></pre></td></tr></table></figure>
<p>可以使用和ruby 1.9类似的<em>lambda函数</em>写法-&gt;来代替function<br>参数列表放在-&gt;的前边，且可省略<br>取消了函数声明，只能将函数作为值定义<br>在CoffeeScript中，任何语句都是表达式(除了break和continue)，都有返回值，因此像ruby一样，不需要显式return<br>js的函数参数有一个很讨厌的地方，就是参数对象arguments不是一个真正的数组，要使用数组方法，必须转换成数组[].slice.call(arguments, 0)这样，而在CoffeeScript中收束(加…)的参数是一个真正的数组<br>CoffeeScript的函数可以有默认参数，如</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">times = (a = <span class="number">1</span>, b = <span class="number">2</span>) -&gt; a * b</div></pre></td></tr></table></figure>
<p>CoffeeScript的函数调用可以不用()语法包围参数，像ruby一样跟在函数名后面就可以，不过这也有时候会带来问题，特别是没有参数的调用</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">alert</div></pre></td></tr></table></figure>
<p>对应的js</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">alert;</div></pre></td></tr></table></figure>
<p>而不是alert()，这和ruby不同，需要注意</p>
<p>缩进的格式有时需要小心，比如用多个函数做参数的时候，需要这样写</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">$(<span class="string">".toggle"</span>).toggle -&gt;</div><div class="line">  <span class="string">"on"</span></div><div class="line">, -&gt;</div><div class="line">  <span class="string">"off"</span></div></pre></td></tr></table></figure>
<p>对应js</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">$(<span class="string">".toggle"</span>).toggle(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</div><div class="line">  <span class="keyword">return</span> <span class="string">"on"</span>;</div><div class="line">&#125;, <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</div><div class="line">  <span class="keyword">return</span> <span class="string">"off"</span>;</div><div class="line">&#125;);</div></pre></td></tr></table></figure>
<h3 id="模式"><a href="#模式" class="headerlink" title="模式"></a>模式</h3><p>使用CoffeeScript的一个重要理由，就是她用自己的语法实现了很多很常用的js编程模式，而且，通常是在社区内广泛被承认的最佳实践，如果不熟悉JavaScript的这些模式，可能会在调试代码上遇到一些麻烦，不过，基本上来说还是比较简单易懂的，下面我们会花一些时间研究一下CoffeeScript是用什么样的方法来封装这些通用编程模式的</p>
<h3 id="闭包"><a href="#闭包" class="headerlink" title="闭包"></a>闭包</h3><p>在js中，普遍会使用闭包实现各种事件的handler或封装模块，以下是CoffeeScript对这一普遍模式的实现</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">closure = do -&gt;</div><div class="line">  _private = "foo"</div><div class="line">  -&gt; _private</div><div class="line"></div><div class="line">console.log(closure()) #=&gt; "foo"</div></pre></td></tr></table></figure>
<p>do关键词可以产生一个Immediate Function,下面是对应js代码</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> closure;</div><div class="line"></div><div class="line">closure = (<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</div><div class="line">  <span class="keyword">var</span> _private;</div><div class="line">  _private = <span class="string">"foo"</span>;</div><div class="line">  <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</div><div class="line">    <span class="keyword">return</span> _private;</div><div class="line">  &#125;;</div><div class="line">&#125;)();</div></pre></td></tr></table></figure>
<p>闭包中经常需要绑定this的值给闭包的私有变量，CoffeeScript使用特殊的=&gt;语法省去了这个麻烦</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">@clickHandler = -&gt; alert <span class="string">"clicked"</span></div><div class="line">element.addEventListener <span class="string">"click"</span>, (e) =&gt; @clickHandler(e)</div></pre></td></tr></table></figure>
<p>使用=&gt;生成函数，可以看到生成代码中会加上对this的绑定</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> _this = <span class="keyword">this</span>;</div><div class="line"></div><div class="line"><span class="keyword">this</span>.clickHandler = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</div><div class="line">  <span class="keyword">return</span> alert(<span class="string">"clicked"</span>);</div><div class="line">&#125;;</div><div class="line"></div><div class="line">element.addEventListener(<span class="string">"click"</span>, <span class="function"><span class="keyword">function</span>(<span class="params">e</span>) </span>&#123;</div><div class="line">  <span class="keyword">return</span> _this.clickHandler(e);</div><div class="line">&#125;);</div></pre></td></tr></table></figure>
<p>这里CoffeeScript对于this有简单的别名@</p>
<h3 id="扩展"><a href="#扩展" class="headerlink" title="扩展"></a>扩展</h3><p>在js中，所有的对象都是开放的，有时候会扩展原有对象的行为(比如对数组的ECMA5 shim)，这也称为Monkey patching</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="built_in">String</span>::dasherize = -&gt; @replace /_/g, <span class="string">"-"</span></div></pre></td></tr></table></figure>
<p>::代表原型的引用，js代码如下</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="built_in">String</span>.prototype.dasherize = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</div><div class="line">  <span class="keyword">return</span> <span class="keyword">this</span>.replace(<span class="regexp">/_/g</span>, <span class="string">"-"</span>);</div><div class="line">&#125;;</div></pre></td></tr></table></figure>
<h3 id="类"><a href="#类" class="headerlink" title="类"></a>类</h3><p>在js中是否要模拟传统编程语言的类，是个一直以来都有争议的话题，不同的项目，不同的团队，在类的使用上会有不同的看法，不过，一旦决定要使用类，那么至少需要一套良好的实现，CoffeeScript在语言内部实现了类的模拟，我们来看一看一个完整的例子</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line">class Gadget</div><div class="line">  @CITY = "beijing"</div><div class="line"></div><div class="line">  @create: (name, price) -&gt;</div><div class="line">    new Gadget(name, price)</div><div class="line"></div><div class="line">  _price = 0</div><div class="line"></div><div class="line">  constructor: (@name, price) -&gt;</div><div class="line">    _price = price</div><div class="line"></div><div class="line">  sell: =&gt;</div><div class="line">    "Buy #&#123;@name&#125; with #&#123;_price&#125; in #&#123;Gadget.CITY&#125;"</div><div class="line"></div><div class="line">iphone = new Gadget("iphone", 4999)</div><div class="line">console.log iphone.name #=&gt; "iphone"</div><div class="line">console.log iphone.sell() #=&gt; "Buy iphone with 4999 in beijing"</div><div class="line"></div><div class="line">ipad = Gadget.create("ipad", 3999)</div><div class="line">console.log ipad.sell() #=&gt; "Buy ipad with 3999 in beijing"</div></pre></td></tr></table></figure>
<p>这个Gadget类具有通常语言中类的功能:</p>
<p>constructor是构造函数，必须用这个名称，类似ruby中的initialize<br>name是实例变量,可以通过iphone.name获取<br>构造函数中如果给实例变量赋值，直接将@name写在参数中即可，等价于在函数体中的@name = name<br>_price是私有变量,需要赋初始值<br>sell是实例方法<br>create是类方法，注意这里使用了@create，这和ruby有些像，在定义时的this指的是这个类本身<br>CITY是类变量<br>要注意的是，对于实例方法，要用=&gt;来绑定this，这样可以作为闭包传递，比如</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">iphone = <span class="keyword">new</span> Gadget(<span class="string">"iphone"</span>, <span class="number">4999</span>)</div><div class="line">$(<span class="string">"#sell"</span>).click(iphone.sell())</div></pre></td></tr></table></figure>
<p>如果不用=&gt;，闭包被调用时就会丢失实例对象的值(iphone)</p>
<p>对于熟悉基于类的面向对象编程的人，CoffeeScript的类是一目了然的，下面来看看对应的js代码</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> Gadget,</div><div class="line">  __bind = <span class="function"><span class="keyword">function</span>(<span class="params">fn, me</span>)</span>&#123; <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123; <span class="keyword">return</span> fn.apply(me, <span class="built_in">arguments</span>); &#125;; &#125;;</div><div class="line"></div><div class="line">Gadget = (<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</div><div class="line">  <span class="keyword">var</span> _price;</div><div class="line"></div><div class="line">  Gadget.name = <span class="string">'Gadget'</span>;</div><div class="line"></div><div class="line">  Gadget.CITY = <span class="string">"beijing"</span>;</div><div class="line"></div><div class="line">  Gadget.create = <span class="function"><span class="keyword">function</span>(<span class="params">name, price</span>) </span>&#123;</div><div class="line">    <span class="keyword">return</span> <span class="keyword">new</span> Gadget(name, price);</div><div class="line">  &#125;;</div><div class="line"></div><div class="line">  _price = <span class="number">0</span>;</div><div class="line"></div><div class="line">  <span class="function"><span class="keyword">function</span> <span class="title">Gadget</span>(<span class="params">name, price</span>) </span>&#123;</div><div class="line">    <span class="keyword">this</span>.sell = __bind(<span class="keyword">this</span>.sell, <span class="keyword">this</span>);</div><div class="line">    <span class="keyword">this</span>.name = name;</div><div class="line">    _price = price;</div><div class="line">  &#125;</div><div class="line"></div><div class="line">  Gadget.prototype.sell = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</div><div class="line">    <span class="keyword">return</span> <span class="string">"Buy "</span> + <span class="keyword">this</span>.name + <span class="string">" with "</span> + _price + <span class="string">" in "</span> + Gadget.CITY;</div><div class="line">  &#125;;</div><div class="line"></div><div class="line">  <span class="keyword">return</span> Gadget;</div><div class="line"></div><div class="line">&#125;)();</div></pre></td></tr></table></figure>
<p>以上的代码有很多值得注意的地方</p>
<p>整体上来说，CoffeeScript的类模拟使用的是一个<em>构造函数闭包</em>，这是最常用的模拟类的模式，好处是可以完整地封装内部变量，且可以使用new来生成实例对象<br>_price就是被封装在闭包内部的私有变量<br>sell这样的实例方法是原型方法，并且在初始化时使用自定义的bind函数绑定实例(用=&gt;定义的情况)<br>create和CITY这样的类成员使用构造函数的属性实现，重复一下，在CoffeeScript类定义中的this指的是整个闭包Gadget<br>Gadget.name是额外定义的类名属性</p>
<h3 id="类的继承"><a href="#类的继承" class="headerlink" title="类的继承"></a>类的继承</h3><p>CoffeeScript中为方便地实现类的继承也定义了自己的语法，我们把上面的类简化，来看一下如何继承：</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line">class Gadget</div><div class="line">  constructor: (@name) -&gt;</div><div class="line">  sell: =&gt;</div><div class="line">    "Buy #&#123;@name&#125;"</div><div class="line"></div><div class="line">class IPhone extends Gadget</div><div class="line">  constructor: -&gt; super("iphone")</div><div class="line">  nosell: =&gt;</div><div class="line">    "Don't #&#123;@sell()&#125;"</div><div class="line"></div><div class="line">iphone = new IPhone</div><div class="line">iphone.nosell() #=&gt; Don't Buy iphone</div></pre></td></tr></table></figure>
<p>使用extends关键字可以继承父类中的所有实例属性,比如sell<br>super方法可以调用父类的同名方法<br>如果不覆盖constructor，则她被子类默认调用<br>来看一下对应的js代码，这有一些复杂，我们把和上边类定义中重复的地方去掉，只留下继承的实现部分</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> Gadget, IPhone,</div><div class="line">  __extends = <span class="function"><span class="keyword">function</span>(<span class="params">child, parent</span>) </span>&#123;</div><div class="line">    <span class="keyword">for</span> (<span class="keyword">var</span> key <span class="keyword">in</span> parent) &#123;</div><div class="line">      <span class="keyword">if</span> (&#123;&#125;.hasOwnProperty.call(parent, key))</div><div class="line">        child[key] = parent[key];</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">function</span> <span class="title">ctor</span>(<span class="params"></span>) </span>&#123; <span class="keyword">this</span>.constructor = child; &#125;</div><div class="line"></div><div class="line">    ctor.prototype = parent.prototype;</div><div class="line">    child.prototype = <span class="keyword">new</span> ctor;</div><div class="line">    child.__super__ = parent.prototype;</div><div class="line"></div><div class="line">    <span class="keyword">return</span> child;</div><div class="line">  &#125;;</div><div class="line"></div><div class="line">IPhone = (<span class="function"><span class="keyword">function</span>(<span class="params">_super</span>) </span>&#123;</div><div class="line"></div><div class="line">  __extends(IPhone, _super);</div><div class="line"></div><div class="line">  IPhone.name = <span class="string">'IPhone'</span>;</div><div class="line"></div><div class="line">  <span class="function"><span class="keyword">function</span> <span class="title">IPhone</span>(<span class="params"></span>) </span>&#123;</div><div class="line">    <span class="keyword">this</span>.nosell = __bind(<span class="keyword">this</span>.nosell, <span class="keyword">this</span>);</div><div class="line">    IPhone.__super__.constructor.call(<span class="keyword">this</span>, <span class="string">"iphone"</span>);</div><div class="line">  &#125;</div><div class="line"></div><div class="line">  IPhone.prototype.nosell = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</div><div class="line">    <span class="keyword">return</span> <span class="string">"Don't "</span> + (<span class="keyword">this</span>.sell());</div><div class="line">  &#125;;</div><div class="line"></div><div class="line">  <span class="keyword">return</span> IPhone;</div><div class="line"></div><div class="line">&#125;)(Gadget);</div></pre></td></tr></table></figure>
<p>这里重点有三个，</p>
<p>__extends函数使用了代理构造函数ctor来实现继承，这是非常普遍的js中对象继承的实践模式，进一步解释一下<br>使用代理构造函数的目的是为了避免子类被更改时父类受到影响<br>使用ctor.prototype = parent.prototype的意义是只继承定义在prototype上的公用属性<br>父类的类成员被直接引用拷贝到子类，而不是原型继承<br>super的实现方法是parent.prototype.constructor.call(this)<br>混入(Mixin)</p>
<p>在ruby语言中的Mixin，能够让你的类获得多个模块的方法，可以说是对多重继承一种很好的实现，虽然在CoffeeScript中并没有像ruby的include一样的内置功能，但很容易实现她</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div></pre></td><td class="code"><pre><div class="line">class Module</div><div class="line">  @extend: (obj) -&gt;</div><div class="line">    for key, value of obj</div><div class="line">      @[key] = value</div><div class="line"></div><div class="line">  @include: (obj) -&gt;</div><div class="line">    for key, value of obj</div><div class="line">      @::[key] = value</div><div class="line"></div><div class="line">classProperties =</div><div class="line">  find: (id) -&gt;</div><div class="line">    console.log("find #&#123;id&#125;")</div><div class="line"></div><div class="line">instanceProperties =</div><div class="line">  save: -&gt;</div><div class="line">    console.log("save")</div><div class="line"></div><div class="line">class User extends Module</div><div class="line">  @extend classProperties</div><div class="line">  @include instanceProperties</div><div class="line"></div><div class="line">user = User.find(1)</div><div class="line">user = new User</div><div class="line">user.save()</div></pre></td></tr></table></figure>
<p>继承了Module的类才可以Mixin，当然，这里也可以用组合或者直接为js的构造函数做Monkey patching<br>classProperties是类成员模块，使用@extend来Mixin，实现是简单的拷贝对象的属性<br>instanceProperties是实例成员模块，使用@include来Mixin，实现是拷贝对象原型的属性<br>需要指出的是，这里的拷贝是引用拷贝，有可能外部会更改被Mixin的模块内部值，更好的方法是深层值拷贝(clone)，包括JQuery在内的很多类库都实现了这类扩展方法</p>
<h3 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h3><p>CoffeeScript提供了一门比JavaScript更强大，优雅，表现力丰富的语言，但她毕竟架构于JavaScript之上，而且是静态地编译成JavaScript代码，也就是说，她不能完全避免对JavaScript中一些不良部分的滥用，比如eval,typeof,instanceof等，所以，在任何情况下，建议始终开启Strict Mode</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="meta">"use strict"</span></div></pre></td></tr></table></figure>
<p>严格模式是一个ECMA5标准提出的js子集，禁用了很多js设计中不好的方面，在未来会逐渐成为js的语言标准，详细介绍在这里</p>

      
    </div>

    <div>
      
        

      
    </div>

    <div>
      
        

      
    </div>


    <footer class="post-footer">
      
        <div class="post-tags">
          
            <a href="/tags/javascript/" rel="tag"># javascript</a>
          
            <a href="/tags/coffeescript/" rel="tag"># coffeescript</a>
          
        </div>
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/2016/03/12/hybrid-cordova-angular2-ionic2-practice-3/" rel="next" title="Hybrid混合开发实践-Cordova/Angular2/Ionic2-工程结构(3)">
                <i class="fa fa-chevron-left"></i> Hybrid混合开发实践-Cordova/Angular2/Ionic2-工程结构(3)
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/2016/05/12/autoit-gitlab-gitlab-ci-mac/" rel="prev" title="基于Docker搭建Gitlab/Gitlab CI测试环境">
                基于Docker搭建Gitlab/Gitlab CI测试环境 <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </article>



    <div class="post-spread">
      
        <div class="ds-share flat" data-thread-key="2016/04/25/web-js-coffeescript/"
     data-title="CoffeeScript 详解(转载)"
     data-content=""
     data-url="http://chrisrc.me/2016/04/25/web-js-coffeescript/">
  <div class="ds-share-inline">
    <ul  class="ds-share-icons-16">

      <li data-toggle="ds-share-icons-more"><a class="ds-more" href="javascript:void(0);">分享到：</a></li>
      <li><a class="ds-weibo" href="javascript:void(0);" data-service="weibo">微博</a></li>
      <li><a class="ds-qzone" href="javascript:void(0);" data-service="qzone">QQ空间</a></li>
      <li><a class="ds-qqt" href="javascript:void(0);" data-service="qqt">腾讯微博</a></li>
      <li><a class="ds-wechat" href="javascript:void(0);" data-service="wechat">微信</a></li>

    </ul>
    <div class="ds-share-icons-more">
    </div>
  </div>
</div>
      
    </div>
  </div>


          </div>
          


          
  <div class="comments" id="comments">
    
      <div class="ds-thread" data-thread-key="2016/04/25/web-js-coffeescript/"
           data-title="CoffeeScript 详解(转载)" data-url="http://chrisrc.me/2016/04/25/web-js-coffeescript/">
      </div>
    
  </div>


        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap" >
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview">
            站点概览
          </li>
        </ul>
      

      <section class="site-overview sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
          <img class="site-author-image" itemprop="image"
               src="/images/avatar.gif"
               alt="chrisrc" />
          <p class="site-author-name" itemprop="name">chrisrc</p>
          <p class="site-description motion-element" itemprop="description"></p>
        </div>
        <nav class="site-state motion-element">
          <div class="site-state-item site-state-posts">
            <a href="/archives">
              <span class="site-state-item-count">69</span>
              <span class="site-state-item-name">日志</span>
            </a>
          </div>

          
            <div class="site-state-item site-state-categories">
              <a href="/categories">
                <span class="site-state-item-count">21</span>
                <span class="site-state-item-name">分类</span>
              </a>
            </div>
          

          
            <div class="site-state-item site-state-tags">
              <a href="/tags">
                <span class="site-state-item-count">162</span>
                <span class="site-state-item-name">标签</span>
              </a>
            </div>
          

        </nav>

        

        <div class="links-of-author motion-element">
          
            
              <span class="links-of-author-item">
                <a href="https://github.com/christtrc" target="_blank" title="GitHub">
                  
                    <i class="fa fa-fw fa-github"></i>
                  
                  GitHub
                </a>
              </span>
            
              <span class="links-of-author-item">
                <a href="https://twitter.com/chrisrc" target="_blank" title="Twitter">
                  
                    <i class="fa fa-fw fa-twitter"></i>
                  
                  Twitter
                </a>
              </span>
            
          
        </div>

        
        
          <div class="cc-license motion-element" itemprop="license">
            <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" class="cc-opacity" target="_blank">
              <img src="/images/cc-by-nc-sa.svg" alt="Creative Commons" />
            </a>
          </div>
        

        
        

        


      </section>

      
      <!--noindex-->
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
              
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#注记"><span class="nav-number">1.</span> <span class="nav-text">注记</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#序"><span class="nav-number">2.</span> <span class="nav-text">序</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#为什么要用CoffeeScript"><span class="nav-number">2.1.</span> <span class="nav-text">为什么要用CoffeeScript?</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#什么情况下不推荐使用CoffeeScript"><span class="nav-number">2.2.</span> <span class="nav-text">什么情况下不推荐使用CoffeeScript?</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#语法"><span class="nav-number">2.3.</span> <span class="nav-text">语法</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#格式"><span class="nav-number">2.4.</span> <span class="nav-text">格式</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#作用域"><span class="nav-number">2.5.</span> <span class="nav-text">作用域</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#赋值"><span class="nav-number">2.6.</span> <span class="nav-text">赋值</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#数组"><span class="nav-number">2.7.</span> <span class="nav-text">数组</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#流程控制"><span class="nav-number">2.8.</span> <span class="nav-text">流程控制</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#函数"><span class="nav-number">2.9.</span> <span class="nav-text">函数</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#模式"><span class="nav-number">2.10.</span> <span class="nav-text">模式</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#闭包"><span class="nav-number">2.11.</span> <span class="nav-text">闭包</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#扩展"><span class="nav-number">2.12.</span> <span class="nav-text">扩展</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#类"><span class="nav-number">2.13.</span> <span class="nav-text">类</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#类的继承"><span class="nav-number">2.14.</span> <span class="nav-text">类的继承</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#结语"><span class="nav-number">2.15.</span> <span class="nav-text">结语</span></a></li></ol></li></ol></div>
            

          </div>
        </section>
      <!--/noindex-->
      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright" >
  
  &copy;  2015 - 
  <span itemprop="copyrightYear">2017</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">
     
      <a href="mailto:chrisrc@qq.com">chrisrc</a> 
    
  </span>
  <span class="author"> &nbsp; QQ: 58122705 </span>
</div>


<div class="powered-by">
  由 <a class="theme-link" href="https://hexo.io">Hexo</a> 强力驱动
</div>

<div class="theme-info">
  主题 -
  <a class="theme-link" href="https://github.com/iissnan/hexo-theme-next">
    NexT.Mist
  </a>
</div>


        

        
      </div>
    </footer>

    <div class="back-to-top">
      <i class="fa fa-arrow-up"></i>
    </div>
  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  



  
  <script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>

  
  <script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>

  
  <script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>

  
  <script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.1.0"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.1.0"></script>



  
  

  
  <script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.0"></script>
<script type="text/javascript" src="/js/src/post-details.js?v=5.1.0"></script>



  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.0"></script>



  

  
    
  

  <script type="text/javascript">
    var duoshuoQuery = {short_name:"chrisrc"};
    (function() {
      var ds = document.createElement('script');
      ds.type = 'text/javascript';ds.async = true;
      ds.id = 'duoshuo-script';
      ds.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') + '//static.duoshuo.com/embed.js';
      ds.charset = 'UTF-8';
      (document.getElementsByTagName('head')[0]
      || document.getElementsByTagName('body')[0]).appendChild(ds);
    })();
  </script>

  
    
    
    <script src="/lib/ua-parser-js/dist/ua-parser.min.js?v=0.7.9"></script>
    <script src="/js/src/hook-duoshuo.js"></script>
  








  
  

  

  

  
<script>
(function(){
    var bp = document.createElement('script');
    var curProtocol = window.location.protocol.split(':')[0];
    if (curProtocol === 'https') {
        bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';        
    }
    else {
        bp.src = 'http://push.zhanzhang.baidu.com/push.js';
    }
    var s = document.getElementsByTagName("script")[0];
    s.parentNode.insertBefore(bp, s);
})();
</script>


  
<script>
(function(){
   var src = (document.location.protocol == "http:") ? "http://js.passport.qihucdn.com/11.0.1.js?ed903ab05fbc5fa64d95e4bfbf3d3a04":"https://jspassport.ssl.qhimg.com/11.0.1.js?ed903ab05fbc5fa64d95e4bfbf3d3a04";
   document.write('<script src="' + src + '" id="sozz"><\/script>');
})();
</script>

  


</body>
</html>
